﻿#include "Util.h"

#include <cstring>
#include <random>
#include <regex>
#include <unistd.h>
#include <iostream>
#include <chrono>

using namespace std;
namespace toolkit {

    static constexpr char CCH[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    
    string makeRandStr(int sz, bool printable) {
        string ret;
        ret.resize(sz);
        std::mt19937 rng(std::random_device{}());
        for (int i = 0; i < sz; ++i) {
            if (printable) {
                uint32_t x = rng() % (sizeof(CCH) - 1);
                ret[i] = CCH[x];
            } else {
                ret[i] = rng() % 0xFF;
            }
        }
        return ret;
    }
    
    bool isSafe(uint8_t b) {
        return b >= ' ' && b < 128;
    }
    
    string hexDump(const void *buf, size_t len) {
        string ret("\r\n");
        char tmp[8];
        const uint8_t *data = (const uint8_t *) buf;
        for (size_t i = 0; i < len; i += 16) {
            for (int j = 0; j < 16; ++j) {
                if (i + j < len) {
                    int sz = snprintf(tmp, sizeof(tmp), "%.2x ", data[i + j]);
                    ret.append(tmp, sz);
                } else {
                    int sz = snprintf(tmp, sizeof(tmp), "   ");
                    ret.append(tmp, sz);
                }
            }
            for (int j = 0; j < 16; ++j) {
                if (i + j < len) {
                    ret += (isSafe(data[i + j]) ? data[i + j] : '.');
                } else {
                    ret += (' ');
                }
            }
            ret += ('\n');
        }
        return ret;
    }
    
    string hexMem(const void *buf, size_t len) {
        string ret;
        char tmp[8];
        const uint8_t *data = (const uint8_t *) buf;
        for (size_t i = 0; i < len; ++i) {
            int sz = sprintf(tmp, "%.2x ", data[i]);
            ret.append(tmp, sz);
        }
        return ret;
    }
    
    string exePath(bool isExe /*= true*/) {
        char buffer[PATH_MAX * 2 + 1] = {0};
        int n = -1;
    #if defined(_WIN32)
        n = GetModuleFileNameA(isExe?nullptr:(HINSTANCE)&__ImageBase, buffer, sizeof(buffer));
    #elif defined(__MACH__) || defined(__APPLE__)
        n = sizeof(buffer);
        if (uv_exepath(buffer, &n) != 0) {
            n = -1;
        }
    #elif defined(__linux__)
        n = readlink("/proc/self/exe", buffer, sizeof(buffer));
    #endif
    
        string filePath;
        if (n <= 0) {
            filePath = "./";
        } else {
            filePath = buffer;
        }
    
    #if defined(_WIN32)
        // windows下把路径统一转换层unix风格，因为后续都是按照unix风格处理的
        for (auto &ch : filePath) {
            if (ch == '\\') {
                ch = '/';
            }
        }
    #endif //defined(_WIN32)
    
        return filePath;
    }
    
    string exeDir(bool isExe /*= true*/) {
        auto path = exePath(isExe);
        return path.substr(0, path.rfind('/') + 1);
    }
    
    string exeName(bool isExe /*= true*/) {
        auto path = exePath(isExe);
        return path.substr(path.rfind('/') + 1);
    }

    // string转小写
    std::string &strToLower(std::string &str) {
        transform(str.begin(), str.end(), str.begin(), towlower);
        return str;
    }

    // string转大写
    std::string &strToUpper(std::string &str) {
        transform(str.begin(), str.end(), str.begin(), towupper);
        return str;
    }

    // string转小写
    std::string strToLower(std::string &&str) {
        transform(str.begin(), str.end(), str.begin(), towlower);
        return std::move(str);
    }

    // string转大写
    std::string strToUpper(std::string &&str) {
        transform(str.begin(), str.end(), str.begin(), towupper);
        return std::move(str);
    }

    vector<string> split(const string &s, const char *delim) {
        vector<string> ret;
        size_t last = 0;
        auto index = s.find(delim, last);
        while (index != string::npos) {
            if (index - last > 0) {
                ret.push_back(s.substr(last, index - last));
            }
            last = index + strlen(delim);
            index = s.find(delim, last);
        }
        if (!s.size() || s.size() - last > 0) {
            ret.push_back(s.substr(last));
        }
        return ret;
    }

#define TRIM(s, chars)                                                     \
        do {                                                                   \
            string map(0xFF, '\0');                                            \
            for (auto &ch : chars) {                                           \
                map[(unsigned char &)ch] = '\1';                               \
            }                                                                  \
            while (s.size() && map.at((unsigned char &)s.back()))              \
                s.pop_back();                                                  \
            while (s.size() && map.at((unsigned char &)s.front()))             \
                s.erase(0, 1);                                                 \
        } while (0);

    // 去除前后的空格、回车符、制表符
    std::string &trim(std::string &s, const string &chars) {
        TRIM(s, chars);
        return s;
    }

    std::string trim(std::string &&s, const string &chars) {
        TRIM(s, chars);
        return std::move(s);
    }

    void replace(string &str, const string &old_str, const string &new_str,
                 std::string::size_type b_pos) {
        if (old_str.empty() || old_str == new_str) {
            return;
        }
        auto pos = str.find(old_str, b_pos);
        if (pos == string::npos) {
            return;
        }
        str.replace(pos, old_str.size(), new_str);
        replace(str, old_str, new_str, pos + new_str.length());
    }

    bool startWith(const string &str, const string &substr) {
        return str.find(substr) == 0;
    }

    bool endWith(const string &str, const string &substr) {
        auto pos = str.rfind(substr);
        return pos != string::npos && pos == str.size() - substr.size();
    }
    bool isIP(const char *str) {
        // 判断是否为 IPv4 地址的正则表达式
        const std::regex ipv4_pattern(R"(^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)");
        // 判断是否为 IPv6 地址的正则表达式
        const std::regex ipv6_pattern(R"(^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$)");
        
        std::string s(str);
        return std::regex_match(s, ipv4_pattern) || std::regex_match(s, ipv6_pattern);
    }

#if defined(_WIN32)
    void sleep(int second) { Sleep(1000 * second); }
    void usleep(int micro_seconds) {
        this_thread::sleep_for(std::chrono::microseconds(micro_seconds));
    }

    int gettimeofday(struct timeval *tp, void *tzp) {
        auto now_stamp =
            std::chrono::duration_cast<std::chrono::microseconds>(
                std::chrono::system_clock::now().time_since_epoch())
                .count();
        tp->tv_sec = (decltype(tp->tv_sec))(now_stamp / 1000000LL);
        tp->tv_usec = now_stamp % 1000000LL;
        return 0;
    }

    const char *strcasestr(const char *big, const char *little) {
        string big_str = big;
        string little_str = little;
        strToLower(big_str);
        strToLower(little_str);
        auto pos = strstr(big_str.data(), little_str.data());
        if (!pos) {
            return nullptr;
        }
        return big + (pos - big_str.data());
    }

    // 实现 vasprintf 函数
    int vasprintf(char **strp, const char *fmt, va_list ap) {
        // 格式化字符串，获取长度
        int len = _vscprintf(fmt, ap);
        if (len == -1) {
            return -1;
        }

        // 分配内存
        char *str = (char *)malloc(len + 1);
        if (!str) {
            return -1;
        }

        // 格式化字符串
        int r = vsnprintf(str, len + 1, fmt, ap);
        if (r == -1) {
            free(str);
            return -1;
        }

        *strp = str;
        return r;
    }

    int asprintf(char **strp, const char *fmt, ...) {
        va_list ap;
        va_start(ap, fmt);
        int r = vasprintf(strp, fmt, ap);
        va_end(ap);
        return r;
    }
#endif // defined(_WIN32)

    // 获取时间差，返回值单位为秒
    long getGMTOff() {
        static long g_GmtOffset = -1;
        if (g_GmtOffset != -1) {
            return g_GmtOffset;
        }

        time_t t = time(nullptr);
        struct tm tm_local;
        struct tm tm_gmt;

#ifdef _WIN32
        localtime_s(&tm_local, &t);
        gmtime_s(&tm_gmt, &t);
#else
        localtime_r(&t, &tm_local);
        gmtime_r(&t, &tm_gmt);
#endif

        g_GmtOffset = mktime(&tm_local) - mktime(&tm_gmt);
        return g_GmtOffset;
    }

    // 获取1970年至今的毫秒数
    uint64_t getCurrentMillisecond(bool systemTime) {
        if (systemTime) {
            // 使用系统时间
            auto now_system = std::chrono::system_clock::now();
            return std::chrono::duration_cast<std::chrono::milliseconds>(
                       now_system.time_since_epoch())
                .count();
        }

        // 使用程序启动时间
        static uint64_t s_currentMillisecond = getCurrentMillisecond(true);
        static uint64_t s_currentMillisecond_system = s_currentMillisecond;
        static uint64_t s_tick =
            std::chrono::steady_clock::now().time_since_epoch().count();

        uint64_t now_steady =
            std::chrono::steady_clock::now().time_since_epoch().count();
        uint64_t ticked = (now_steady - s_tick) /
                          (std::chrono::steady_clock::period::den /
                           std::chrono::steady_clock::period::num / 1000);
        return s_currentMillisecond + ticked;
    }

    // 获取1970年至今的微秒数
    uint64_t getCurrentMicrosecond(bool systemTime) {
        if (systemTime) {
            // 使用系统时间
            auto now_system = std::chrono::system_clock::now();
            return std::chrono::duration_cast<std::chrono::microseconds>(
                       now_system.time_since_epoch())
                .count();
        }

        // 使用程序启动时间
        static uint64_t s_currentMicrosecond = getCurrentMicrosecond(true);
        static uint64_t s_currentMicrosecond_system = s_currentMicrosecond;
        static uint64_t s_tick =
            std::chrono::steady_clock::now().time_since_epoch().count();

        uint64_t now_steady =
            std::chrono::steady_clock::now().time_since_epoch().count();
        uint64_t ticked = (now_steady - s_tick) /
                          (std::chrono::steady_clock::period::den /
                           std::chrono::steady_clock::period::num / 1000000);
        return s_currentMicrosecond + ticked;
    }

    // 获取时间字符串
    string getTimeStr(const char *fmt, time_t time) {
        if (!time) {
            time = ::time(nullptr);
        }

        auto tm = getLocalTime(time);
        char buffer[64];
        auto success = std::strftime(buffer, sizeof(buffer), fmt, &tm);
        return 0 == success ? string(fmt) : buffer;
    }

    // 根据unix时间戳获取本地时间
    struct tm getLocalTime(time_t sec) {
        struct tm tm;
#ifdef _WIN32
        localtime_s(&tm, &sec);
#else
        localtime_r(&sec, &tm);
#endif
        return tm;
    }

    static thread_local string thread_name;

    static string limitString(const char *name, size_t max_size) {
        string str = name;
        if (str.size() + 1 > max_size) {
            auto erased = str.size() + 1 - max_size + 3;
            str.replace(5, erased, "...");
        }
        return str;
    }

    // 设置线程名
    void setThreadName(const char *name) {
#if defined(__linux) || defined(__linux__) || defined(__MINGW32__)
        pthread_setname_np(pthread_self(), limitString(name, 16).data());
#elif defined(__MACH__) || defined(__APPLE__)
        pthread_setname_np(limitString(name, 32).data());
#elif defined(_MSC_VER)
        // 微软平台
#pragma pack(push, 8)
        struct ThreadName {
            DWORD dwType;     // 必须是0x1000
            LPCSTR szName;    // 线程名称，在调试器中可见
            DWORD dwThreadID; // 线程ID
            DWORD dwFlags;    // 保留参数，必须为0
        };
#pragma pack(pop)

        ThreadName info;
        info.dwType = 0x1000;
        info.szName = name;
        info.dwThreadID = GetCurrentThreadId();
        info.dwFlags = 0;

        __try {
            RaiseException(0x406D1388, 0, sizeof(info) / sizeof(ULONG_PTR),
                           (ULONG_PTR *)&info);
        } __except (EXCEPTION_EXECUTE_HANDLER) {
        }
#endif
    }

    // 获取线程名
    string getThreadName() {
        string ret;
#if defined(__linux) || defined(__linux__)
        char name[32] = {0};
        pthread_getname_np(pthread_self(), name, sizeof(name));
        ret = name;
#elif defined(__MACH__) || defined(__APPLE__)
        char name[32] = {0};
        pthread_t thread = pthread_self();
        pthread_getname_np(thread, name, sizeof(name));
        ret = name;
#elif defined(_MSC_VER)
        // Windows平台暂不支持获取线程名称
#endif
        return ret;
    }

    // 设置当前线程cpu亲和性
    bool setThreadAffinity(int i) {
#if defined(__linux) || defined(__linux__)
        cpu_set_t mask;
        CPU_ZERO(&mask);
        if (i != -1) {
            CPU_SET(i, &mask);
        } else {
            for (int j = 0; j < CPU_SETSIZE; ++j) {
                CPU_SET(j, &mask);
            }
        }

        if (!pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask)) {
            return true;
        }

        std::cout << "pthread_setaffinity_np failed: " /*<< get_uv_errmsg()*/ << endl;
        return false;
#else
        return false;
#endif
    }

    // 根据typeid(class).name()获取类名
    string demangle(const char *mangled) {
#if HAS_CXA_DEMANGLE
        int status = 0;
        char *demangled =
            abi::__cxa_demangle(mangled, nullptr, nullptr, &status);
        if (demangled) {
            string result(demangled);
            free(demangled);
            return result;
        }
#endif
        return mangled;
    }

    // 获取环境变量内容，以'$'开头
    string getEnv(const string &key) {
        if (key.empty() || key[0] != '$') {
            return key;
        }

        string name = key.substr(1);
        char *ret = getenv(name.data());
        if (!ret) {
            return "";
        }
        return ret;
    }

    // 异常处理
    void Creator::onDestoryException(const std::type_info &info,
                                     const std::exception &ex) {
        // std::count << "捕获到onDestory函数抛异常, 类型:" << demangle(info.name())
        //       << ", 内容:" << ex.what() << endl;
        std::cout << "捕获到onDestory函数抛异常\n";
    }

    // 断言失败处理
    void Assert_Throw(int failed, const char *exp, const char *func,
                      const char *file, int line, const char *str) {
        if (failed) {
            throw AssertFailedException((str ? str : exp));
        }
    }

    } // namespace toolkit

    extern "C" {
    void Assert_Throw(int failed, const char *exp, const char *func,
                      const char *file, int line, const char *str) {
        if (failed) {
            toolkit::_StrPrinter printer;
            printer << "Assertion failed: (" << exp;
            if (str && *str) {
                printer << ", " << str;
            }
            printer << "), function " << func << ", file " << file << ", line "
                    << line << ".";
            throw toolkit::AssertFailedException(printer);
        }
    }
    }